﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using Clandestine;
using System.Drawing;
using System.Drawing.Design;
using System.Windows.Forms;
using System.Windows.Forms.PropertyGridInternal;
using System.ComponentModel;

namespace Slick.MapEditor.Tools
{
    // The tool
    public class Selection : ITool
    {
        public Map Map;
        public string Name { get { return "Selection"; } }

        /// <summary>
        /// A signal to allow you to wait for a selection to be made
        /// </summary>
        public EventWaitHandle SelectionCompleteSignal = new EventWaitHandle(false, EventResetMode.ManualReset);

        /// <summary>
        /// Whether we got a selection or not (if the user switched to an another tool we wouldnt have one).
        /// </summary>
        public bool HasSelection = false;

        /// <summary>
        /// The selection made using the tool.
        /// </summary>
        public Rectangle SelectionRect = new Rectangle();

        /// <summary>
        /// The sprite used for the previews as we drag the mouse.
        /// </summary>
        private static Sprite hoverSprite;

        /// <summary>
        /// The sprite used for the previews of the previous selection.
        /// </summary>
        public static Sprite previousSprite;

        /// <summary>
        /// Whether the mouse button is being held down.
        /// </summary>
        private bool down = false;

        /// <summary>
        /// The point at which the mouse was pressed down - to allow dragging.
        /// </summary>
        private Point downPosition = new Point();

        // Okay, time for some trickery.
        // We need to add an event thingy for the SelectionUITypeEditor, which is basically a class
        // that allows properties of entities in the PropertyGrid to have the user draw 'selections' on the screen
        // To do this, we'll have a static constructor add it, and have the event handler access the Selection tool
        // of the currently in use map -- and foolishly assume that this event will only ever fire when we're editing
        // a map
        static Selection()
        {
            Clandestine.Entities.SelectionUITypeEditor.DoSelection = new Clandestine.Entities.DoSelection(delegate(object value)
            {
                // Call current map's Selection tool
                ToolController tc = ((MapMode)Editor.CurrentMode).ToolController;
                ITool oldTool = tc.CurrentTool;
                tc.SetMode(Mode.Selection);
                Selection selectTool = (Selection)tc.CurrentTool;

                // Setup previous selection
                Rectangle prev = (Rectangle)value;
                previousSprite = new Sprite(Texture.GetTexture("white.png"));
                previousSprite.Color = new GLColor(1f, 1f, 1f, 0.6f);
                previousSprite.Visible = true;
                previousSprite.ScaleX = prev.Width;
                previousSprite.ScaleY = prev.Height;
                previousSprite.Position = new Point(prev.X, prev.Y);
                previousSprite.Layer = 5000000;

                // Wait for selection to be made
                selectTool.SelectionCompleteSignal.WaitOne();

                // Did we get one?
                Rectangle ret = new Rectangle();
                if (!selectTool.HasSelection)
                    return value;
                else
                    ret = selectTool.SelectionRect;

                // Reset signal
                selectTool.SelectionCompleteSignal.Reset();

                // Reset tool
                previousSprite.Dispose();
                tc.CurrentTool = oldTool;
                return ret;
            });
        }

        public Selection(Map map)
        {
            this.Map = map;
            hoverSprite = new Sprite(Texture.GetTexture("white.png"));
            hoverSprite.Visible = false;
            hoverSprite.Color = new GLColor(0f, 1f, 1f, 0.6f);
        }

         ~Selection()
        {
            hoverSprite.Dispose();
        }

        public void Focus()
        {
        }

        public void Unfocus()
        {
            SelectionCompleteSignal.Set();
        }

        public void MouseUpLeft(int mouseX, int mouseY, int tileX, int tileY)
        {
            // Make sure we're on a grid boundary.
            mouseX += Program.GridSize - (mouseX % Program.GridSize);
            mouseY += Program.GridSize - (mouseY % Program.GridSize);

            // get co-ords of top left of the selection - note, we can move the mouse behind the original point
            // so must handle this!
            Point topLeft = new Point();
            topLeft.X = (mouseX < downPosition.X ? mouseX : downPosition.X);
            topLeft.Y = (mouseY < downPosition.Y ? mouseY : downPosition.Y);

            // get co-ords of the bottom right
            Point bottomRight = new Point();
            bottomRight.X = (mouseX > downPosition.X ? mouseX : downPosition.X);
            bottomRight.Y = (mouseY > downPosition.Y ? mouseY : downPosition.Y);

            // Hide hover
            hoverSprite.Visible = false;
            down = false;
            downPosition = new Point(-1, -1);

            // We're done here
            SelectionRect = new Rectangle(topLeft.X, topLeft.Y, bottomRight.X - topLeft.X, bottomRight.Y - topLeft.X);
            HasSelection = true;
            SelectionCompleteSignal.Set();
        }

        public void MouseDownLeft(int mouseX, int mouseY, int tileX, int tileY)
        {
            // Remember we went down
            down = true;
            downPosition = new Point(mouseX, mouseY);

            // Show a preview hover.
            hoverSprite.Visible = true;
            hoverSprite.Position = new System.Drawing.Point(mouseX, mouseY);
            hoverSprite.ScaleX = 0f;
            hoverSprite.ScaleY = 0f;
            hoverSprite.Layer = 5000000;
        }

        public void MouseUpRight(int mouseX, int mouseY, int tileX, int tileY)
        {

        }


        public void MouseDownRight(int mouseX, int mouseY, int tileX, int tileY)
        {

        }

        public void MouseMove(int mouseX, int mouseY, int tileX, int tileY)
        {
            // Are we drawing
            if (down)
            {
                mouseX += Program.GridSize - (((int)(mouseX / Camera.Zoom)) % Program.GridSize); // rounding errors in finding tileX/Y, so we fix them
                mouseY += Program.GridSize - (((int)(mouseY / Camera.Zoom)) % Program.GridSize);

                // get co-ords of top left of the selection - note, we can move the mouse behind the original point
                // so must handle this!
                Point topLeft = new Point();
                topLeft.X = (mouseX < downPosition.X ? mouseX : downPosition.X);
                topLeft.Y = (mouseY < downPosition.Y ? mouseY : downPosition.Y);

                // get co-ords of the bottom right
                Point bottomRight = new Point();
                bottomRight.X = (mouseX > downPosition.X ? mouseX : downPosition.X);
                bottomRight.Y = (mouseY > downPosition.Y ? mouseY : downPosition.Y);

                hoverSprite.Visible = true;
                hoverSprite.ScaleX = (bottomRight.X - topLeft.X);
                hoverSprite.ScaleY = (bottomRight.Y - topLeft.Y);
                hoverSprite.Position = new Point(topLeft.X, topLeft.Y);
                hoverSprite.Layer = 5000000;
            }
        }
    }
}
